package com.headStorm.socket.mina;

import lombok.Value;
import org.apache.mina.core.filterchain.IoFilter;
import org.apache.mina.core.filterchain.IoFilterAdapter;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.service.IoHandler;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.transport.socket.nio.NioSocketConnector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetSocketAddress;

public class TcpClient {

    private static Logger log = LoggerFactory.getLogger(TcpClient.class); // 日志对象
    private NioSocketConnector connector = new NioSocketConnector(); // TCP客户端连接对象

    // TCP服务器IP地址
    private String serverIP = "127.0.0.1";

    // TCP服务器端口号
    private int serverPort = 60001;
    private int readBufSize = 4096000; // Session读缓冲区大小
    //空闲时间
    private int idleTime = 500000000; // Session进入空闲状态的时间间隔，单位秒 10 * 60
    private int connectTimeout = 30; // 连接超时时间，单位秒 30

    private IoFilter filter = null; // 编解码，过滤器
    private IoHandler handler = null;// 处理器
    private IoSession session = null; // 客户端连接会话对象
    private InetSocketAddress inetSocketAddress = null;

    private int reconnectTime;

    // 初始化参数
    public void initial() {
        try {

            if (inetSocketAddress == null) {
                inetSocketAddress = new InetSocketAddress(serverIP, serverPort);
            }
            connector.getFilterChain().addFirst("reconnection", new IoFilterAdapter() {
                @Override
                public void sessionClosed(NextFilter nextFilter, IoSession session) throws Exception {
                    for (; ; ) {
//                        int port = ((InetSocketAddress) session.getRemoteAddress()).getPort();
//                        try {
//                            Thread.sleep(3000);
//                            ConnectFuture future = connector.connect(new InetSocketAddress(serverIP, port));
//                            future.awaitUninterruptibly();// 等待连接创建成功
//                            session = future.getSession();// 获取会话
//                            if (session.isConnected()) {
//                                System.out.println("adwda");
//                                //log.info("断线重连[" + connector.getDefaultRemoteAddress().getHostName() + ":" + connector.getDefaultRemoteAddress().getPort() + "]成功");
//                                break;
//                            }
//                        } catch (Exception ex) {
//                            ex.printStackTrace();
//                            log.info("重连服务器发生异常:" + ex.getMessage());
//                            log.info("重连服务器登录失败,3秒再连接一次");
//                        }
                        log.info("尝试进行重连操作");
                        boolean reconnect = reconnect();
                        if (reconnect) {
                            log.info("重连成功");
                            break;
                        }
                        Thread.currentThread().sleep(reconnectTime * 1000);
                    }
                }
            });

            // 设置session的读缓冲区大小
            connector.getSessionConfig().setReadBufferSize(readBufSize);
            // 设置session的进入空闲时间间隔
            connector.getSessionConfig().setIdleTime(IdleStatus.READER_IDLE,
                    idleTime);
            connector.setConnectTimeoutMillis(connectTimeout * 1000); // 设置连接超时时间
            // 加载编解码，过滤器
            if (filter != null) {
                connector.getFilterChain().addLast("codec", filter);
            }
            // 加载处理器
            if (handler != null) {
                connector.setHandler(handler);
            }
        } catch (Exception e) {
            // TODO: handle exception
            log.error(e.getMessage());
        }
    }

    public boolean reconnect() {
        log.info("正在重连......");
        boolean flag = false;
        try {
            ConnectFuture future = connector.connect(inetSocketAddress);
            future.awaitUninterruptibly();// 等待连接创建成功
            session = future.getSession();// 获取会话
            if (session.isConnected()) {
                flag = true;
            }
        } catch (Exception exception) {
            log.error(exception.getMessage(), exception);
        }
        return flag;
    }

    // 连接TCP服务器
    public boolean connect() {
        boolean flag = false;
        try {
            // 连接服务器
            ConnectFuture cf = connector.connect(inetSocketAddress);
            log.info("Connecting TCP Server...IP Address:" + serverIP
                    + " Port:" + serverPort);
            // 等待连接创建完成
            cf.awaitUninterruptibly();
            session = cf.getSession();
            log.info("Connected successfully");
            flag = true;

        } catch (Exception e) {
            flag = false;
            // TODO: handle exception
            log.error(e.getMessage(), e);
        }
        return flag;
    }

    // 关闭连接
    public void close() {
        try {
            if (connector != null) {
                session.close();
                // connector.dispose();
            }

        } catch (Exception e) {
            // TODO: handle exception
            log.error(e.getMessage());
        }
    }

    // 释放资源
    public void dispose() {
        try {
            if (connector != null) {
                // session.close();
                connector.dispose();
            }

        } catch (Exception e) {
            // TODO: handle exception
            log.error(e.getMessage());
        }
    }

    // 发送数据
    public void send(Object data) {
        try {
            if (session != null) {
                session.write(data);
            }
        } catch (Exception e) {
            // TODO: handle exception
        }
    }

    public NioSocketConnector getConnector() {
        return connector;
    }

    public void setConnector(NioSocketConnector value) {
        connector = value;
    }

    public String getServerIP() {
        return serverIP;
    }

    public void setServerIP(String value) {
        serverIP = value;
    }

    public int getReadBufSize() {
        return readBufSize;
    }

    public void setReadBufSize(int value) {
        readBufSize = value;
    }

    public int getIdleTime() {
        return idleTime;
    }

    public void setIdleTime(int value) {
        idleTime = value;
    }

    public int getServerPort() {
        return serverPort;
    }

    public void setServerPort(int value) {
        serverPort = value;
    }

    public IoFilter getFilter() {
        return filter;
    }

    public void setFilter(IoFilter value) {
        filter = value;
    }

    public IoHandler getHandler() {
        return handler;
    }

    public void setHandler(IoHandler value) {
        handler = value;
    }

    public int getConnectTimeout() {
        return connectTimeout;
    }

    public void setConnectTimeout(int value) {
        connectTimeout = value;
    }

    public IoSession getSession() {
        return session;
    }

}
